package cn.edu.hust.cm.lib;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;

/**
 * 网络相关的工具类
 * 
 * @author chenming 2012-11-28
 * 
 */
public class NetUtils {

	public static final String INVALID_INET_ADDRESS = "0.0.0.0";

	/**
	 * 返回第一个ipv4地址
	 * 
	 * @return
	 */
	public static String getHostIp() {
		Enumeration<NetworkInterface> en = null;
		try {
			en = NetworkInterface.getNetworkInterfaces();
		} catch (SocketException e) {
			return INVALID_INET_ADDRESS;
		}
		while (en.hasMoreElements()) {
			NetworkInterface iface = en.nextElement();
			Enumeration<InetAddress> info = iface.getInetAddresses();
			while (info.hasMoreElements()) {
				InetAddress addr = info.nextElement();
				// only accept ipv4 addr
				if (!addr.isLoopbackAddress() && addr instanceof Inet4Address) {
					return addr.getHostAddress();
				}
			}
		}
		return INVALID_INET_ADDRESS;
	}

	/**
	 * 获取ip地址为localAddr的网卡上的介于start(不包含)和end(不包含)之间的随机空闲端口
	 * 
	 * @param start
	 *            起始端口, 若小于0将被自动调整为0.
	 * @param end
	 *            结束端口, 若大于65536将自动被调整为65535
	 * @param localAddr
	 *            一个xxx.xxx.xxx.xxx形式的ip地址, 可以为null
	 * @return 一个空闲随机端口
	 */
	public static int getRandomPort(int start, int end, String localAddr) {

		if (start < 0 || end > 65535 || start > end) {
			throw new IllegalArgumentException("error port");
		}

		InetAddress addr = null;
		try {
			if (null == localAddr || 0 == localAddr.length()) {
				addr = InetAddress.getByName(getHostIp());
			} else {
				addr = InetAddress.getByName(localAddr);
			}
		} catch (UnknownHostException e1) {
			// ignore
		}

		if (null == addr) {
			return -1;
		}

		int randPort = -1;
		int retry = 15;
		while (!(randPort > start && randPort < end) && retry-- > 0) {
			try {
				ServerSocket server = new ServerSocket(0, 2, addr);
				randPort = server.getLocalPort();
				server.close();
			} catch (IOException e) {
				// ignore
			}
		}
		return randPort;
	}
}
